// SPDX-FileCopyrightText: 2023 CitruS Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

package com.fanwj.citrus

import android.app.ActivityManager
import android.app.Application
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
import android.os.ParcelFileDescriptor
import android.os.VibrationEffect
import android.os.VibratorManager
import android.system.Os
import com.fanwj.citrus.features.input.NativeInput
import com.fanwj.citrus.utils.DirectoryInitialization
import com.fanwj.citrus.utils.DocumentsTree
import com.fanwj.citrus.utils.GpuDriverHelper
import com.fanwj.citrus.utils.Log
import java.io.File
import kotlin.system.exitProcess


fun Context.getPublicFilesDir(): File = getExternalFilesDir(null) ?: filesDir

class CitrusApplication : Application() {
    private fun createNotificationChannels() {
        val noticeChannel = NotificationChannel(
            getString(R.string.notice_notification_channel_id),
            getString(R.string.notice_notification_channel_name),
            NotificationManager.IMPORTANCE_HIGH
        )
        noticeChannel.description = getString(R.string.notice_notification_channel_description)
        noticeChannel.setSound(null, null)

        // Register the channel with the system; you can't change the importance
        // or other notification behaviors after this
        val notificationManager = getSystemService(NotificationManager::class.java)
        notificationManager.createNotificationChannel(noticeChannel)
    }

    override fun onCreate() {
        super.onCreate()
        application = this
        documentsTree = DocumentsTree()
        startBackend()
        DirectoryInitialization.start()
        GpuDriverHelper.initializeDriverParameters()
        NativeInput.reloadInputDevices()
        NativeLibrary.logDeviceInfo()
        Log.logDeviceInfo()

        createNotificationChannels()
    }

    fun vibrate(milliseconds: Long, amplitude: Int) {
        val vibratorManager = getSystemService(VIBRATOR_MANAGER_SERVICE) as VibratorManager
        val vibrationEffect = VibrationEffect.createOneShot(milliseconds, amplitude)
        (if (vibratorManager.vibratorIds.isNotEmpty())
            vibratorManager.getVibrator(vibratorManager.vibratorIds.last())
        else
            vibratorManager.defaultVibrator).vibrate(vibrationEffect)
    }

    private fun startBackend() {
        try {
            val fd = ParcelFileDescriptor.open(File(applicationInfo.nativeLibraryDir, "libcitrus.so"), ParcelFileDescriptor.MODE_READ_ONLY)
            Os.setenv("CITRUS_BACKEND_ID", fd.fd.toString(), true)
            Os.setenv("LD_PRELOAD", "${applicationInfo.nativeLibraryDir}/libpreload.so", true)
            System.loadLibrary("citrus-android")
            Thread {
                Backend.initialize(fd).start()
                NativeLibrary.waitForMainLooper()
            }.run {
                start()
                join(4000)
                if (!isAlive) {
                    return@startBackend
                }
            }
        }
        catch (e : Exception) {
            e.printStackTrace()
        }
        exit()
    }

    fun exit() {
        (getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager).appTasks.forEach { it.finishAndRemoveTask() }
        exitProcess(-1)
    }

    companion object {
        var documentsTree: DocumentsTree? = null
        lateinit var application: CitrusApplication

        lateinit var connection : Backend
        val appContext: Context
            get() = application.applicationContext
    }
}
